package model.gastos;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.HashMap;
import java.util.Map;

import model.gastos.ConfiguracionGeneral;
import model.gastos.TEM;

import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Test;

/**
 * 
 * @author Damian
 *
 */

public class ConfiguracionGeneralTest {
	
	private ConfiguracionGeneral configuracion;
	private LocalDate hoy;
	private Map<Integer, TEM> tablaTEM;
	
	/**
	 * En este setup se crean los dobles de los DOC necesarios para el SUT, que en
	 * este caso seria el metodo "public TEM getTEMDeCuota(int cuotas)"
	 * Notar que no hice un mock para el Map<Integer, TEM>, ya que este objeto
	 * Map<A,B> es propio de Java y se conoce su correcto funcionamiento
	 */
	@Before 
	public void inicializarTest() {
		this.tablaTEM = new HashMap<Integer, TEM>();
		
		TEM tem3 = mock(TEM.class);
		when(tem3.getPorcentaje()).thenReturn(3.0);
		TEM tem45 = mock(TEM.class);
		when(tem45.getPorcentaje()).thenReturn(4.5);
		TEM tem6 = mock(TEM.class);
		when(tem6.getPorcentaje()).thenReturn(6.0);
		TEM tem9 = mock(TEM.class);
		when(tem9.getPorcentaje()).thenReturn(9.0);
		
		tablaTEM.put(12, tem3);
		tablaTEM.put(18, tem45);
		tablaTEM.put(24, tem6);
		tablaTEM.put(36, tem9);
		
		this.hoy=new LocalDate();
		configuracion = new ConfiguracionGeneral(hoy,500, tablaTEM, 20, 100);
	}
	
	
	
	/**
	 * En este caso testea que el de correcto si el valor de cuotas dado 
	 * es menor a la cantidad de coutas menor (en este caso 12)
	 */
	@Test
	public void menorAlPrimerTEM() {
		testTEM(3.0, 0);
	}
	
	/**
	 * En este caso testea que el de correcto si el valor de cuotas dado 
	 * es mayor a la cantidad de coutas mayor (en este caso 36)
	 */
	@Test
	public void mayorAlUltimoTEM() {
		testTEM(9, 37);
	}
	
	/**
	 * En este caso testea que el de correcto si el valor de cuotas dado 
	 * es exactamente igual cantidad de coutas dada (en este caso 18)
	 */
	@Test
	public void exactamenteUnTEM() {
		testTEM(4.5, 18);
	}
	
	/**
	 * En este caso testea que el de correcto si el valor de cuotas dado 
	 * esta entre medio de dos meses (en este caso entre 18 y 24)
	 */
	@Test
	public void entreTEMS() {
		testTEM(6, 19);	
	}
	
	/**
	 * Este es el codigo comun a todos los anteriores test, donde se invoca al metodo
	 * public TEM getTEMDeCuota(int cuotas)
	 */
	private void testTEM(double esperado, int cuotas) {
		double actual = configuracion.getTEMDeCuota(cuotas).getPorcentaje();
		assertEquals(esperado, actual, 0.1);
	}	
	
	@Test
	public void estaEnVigenteLaUnicaTest(){
		assertTrue(this.configuracion.estaVigente());
	}
	
	@Test
	public void testConfiguracionFinalizadaNoEstaVigente(){
		this.configuracion.finalizar(this.hoy);
		assertFalse(this.configuracion.estaVigente());
	}
	
	@Test
	public void testConfiguracionPorAdelantadoNoEstaVigente(){
		ConfiguracionGeneral configuracionAdelantada = new ConfiguracionGeneral(hoy.plusDays(7),500, tablaTEM, 20, 100);
		assertFalse(configuracionAdelantada.estaVigente());
	}
	
	@Test
	public void tesGetFechaInicio(){
		assertEquals(hoy,this.configuracion.getFechaInicio());
	}
	
	@Test
	public void testGetGastoFijo(){
		assertEquals(100.0,this.configuracion.getGastoFijo(),0.000000001);
	}

	@Test
	public void testGetGastosAdministrativosMensuales(){
		assertEquals(20.0,this.configuracion.getGastosAdministrativosMensuales(),0.000000001);
	}
	
	@Test
	public void testGetGastosGlobalesDeOtorgamiento(){
		assertEquals(500.0,this.configuracion.getGastosGlobalesDeOtorgamiento(),0.000000001);
	}

}
